﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Cemit.PolyProto;
using UnityEngine;
using Cemit.NetFramework.Logger;
using Debug = Cemit.NetFramework.Logger.Debug;

namespace Cemit.NetFramework
{
    static class PlayerExtension
    {
        [Obsolete]
        /// <summary>
        /// 获取角色属性
        /// </summary>
        public static IDictionary<string, object> GetPlayerPropertys(this IPlayerData player)
        {
            return player
               .GetType()
               .GetProperties()
               .Where(IsPlayerProperty)
               .ToDictionary(p => p.Name, p => p.GetValue(player));

            bool IsPlayerProperty(PropertyInfo info)
                => info.GetCustomAttributes().Any(IsPlayerPropertyAttribute);

            bool IsPlayerPropertyAttribute(Attribute attribute)
                => attribute.GetType() == typeof(PlayerPropertyAttribute);
        }

        public static IDictionary<FieldInfo, object> GetPropertyValues(this IPlayerData player)
        {
            return player
                .GetType()
                .GetFields()
                .ToDictionary(f => f, f => f.GetValue(player));
        }


        public static PlayerData GetMessageData(this IPlayerData player)
        {
            var ret = new PlayerData
            {
                Id = player.ID
            };

            foreach (KeyValuePair<FieldInfo, object> item in player.GetPropertyValues())
            {
                switch (item.Value)
                {
                    case int i:
                        ret.IntPropertys.Add(item.Key.Name, i);
                        break;
                    case float f:
                        ret.FloatPropertys.Add(item.Key.Name, f);
                        break;
                    case string s:
                        ret.StringPropertys.Add(item.Key.Name, s);
                        break;
                    case bool b:
                        ret.BoolPropertys.Add(item.Key.Name, b);
                        break;
                    case Vector2 vector2:
                        ret.FloatPropertys.Add(item.Key.Name + "X", vector2.x);
                        ret.FloatPropertys.Add(item.Key.Name + "Y", vector2.y);
                        break;
                    case Vector3 vector3:
                        ret.FloatPropertys.Add(item.Key.Name + "X", vector3.x);
                        ret.FloatPropertys.Add(item.Key.Name + "Y", vector3.y);
                        ret.FloatPropertys.Add(item.Key.Name + "Z", vector3.z);
                        break;
                    case Quaternion quaternion:
                        ret.FloatPropertys.Add(item.Key.Name + "X", quaternion.x);
                        ret.FloatPropertys.Add(item.Key.Name + "Y", quaternion.y);
                        ret.FloatPropertys.Add(item.Key.Name + "Z", quaternion.z);
                        ret.FloatPropertys.Add(item.Key.Name + "W", quaternion.w);
                        break;
                    default:
                        Debug.LogWarning(
                            $"PlayerData的{item.Key.Name}({item.Key.FieldType})属性未被发出：" +
                            $"不支持的类型！" +
                            $"(支持的变量类型为Int32,Float,String,Boolean,Vector2,Vector3和Quaternion)");
                        break;
                }
            }
            return ret;
        }

        public static IPlayerData SetValue(this IPlayerData player, PlayerData playerData)
        {
            player.ID = playerData.Id;
            foreach (KeyValuePair<FieldInfo, object> item in player.GetPropertyValues())
            {
                if (item.Value is int)
                {
                    SetBaseData(playerData.IntPropertys, item.Key);
                }
                else if (item.Value is float)
                {
                    SetBaseData(playerData.FloatPropertys, item.Key);
                }
                else if (item.Value is bool)
                {
                    SetBaseData(playerData.BoolPropertys, item.Key);
                }
                else if (item.Value is string)
                {
                    SetBaseData(playerData.StringPropertys, item.Key);
                }
                else if (item.Value is Vector2)
                {
                    SetVector2(item.Key);
                }
                else if (item.Value is Vector3)
                {
                    SetVector3(item.Key);
                }
                else if (item.Value is Quaternion)
                {
                    SetQuaternion(item.Key);
                }
                else
                {
                    Debug.LogWarning(
                        $"PlayerData的{item.Key.Name}({item.Key.FieldType})属性未被读取：" +
                        $"不支持的类型！" +
                        $"(支持的变量类型为Int32,Float,String,Boolean,Vector2,Vector3和Quaternion)");
                }
            }

            return player;

            bool SetBaseData<T>(IDictionary<string, T> propertysMap, FieldInfo fileInfo)
            {
                if (!propertysMap.ContainsKey(fileInfo.Name))
                {
                    Debug.LogWarning($"没有找到数据：{fileInfo.Name}");
                    return false;
                }

                fileInfo.SetValue(player, propertysMap[fileInfo.Name]);
                return true;
            }

            void SetVector2(FieldInfo fileInfo)
            {
                if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "X", out float x))
                {
                    if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "Y", out float y))
                    {
                        fileInfo.SetValue(player, new Vector2(x, y));
                        return;
                    }
                }
                Debug.LogWarning($"没有找到数据：{fileInfo.Name}");
            }

            void SetVector3(FieldInfo fileInfo)
            {
                if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "X", out float x))
                {
                    if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "Y", out float y))
                    {
                        if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "Z", out float z))
                        {
                            fileInfo.SetValue(player, new Vector3(x, y, z));
                            return;
                        }
                    }
                }
                Debug.LogWarning($"没有找到数据：{fileInfo.Name}");
            }

            void SetQuaternion(FieldInfo fileInfo)
            {
                if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "X", out float x))
                {
                    if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "Y", out float y))
                    {
                        if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "Z", out float z))
                        {
                            if (playerData.FloatPropertys.TryGetValue(fileInfo.Name + "W", out float w))
                            {
                                fileInfo.SetValue(player, new Quaternion(x, y, z, w));
                                return;
                            }
                        }
                    }
                }
                Debug.LogWarning($"没有找到数据：{fileInfo.Name}");
            }
        }
    }
}
